package com.dattplace.mongoSupport;


import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.query.Criteria;

import com.dattplace.util.StringUtil;



 

/**
 * 构建查询条件参数的工具类.. <br>
 * @author chenxiangbai <br>
 * @version 1.0.0 2014-1-7 上午10:15:36 <br>
 * @see Criteria
 * @since JDK 1.7.0
 */
public final class QueryParamCreator {

	/**
	 * 默认构�?�函�?. <br>
	 * @author chenxiangbai 2014-1-7 上午11:07:54 <br>
	 */
	private QueryParamCreator() {
	}
	
	/**
	 * 等于
	 * 说明�?1.属�?��?�value为null，不返回数据�?
	 * 	   2.属�?��?�value�?"",查询propertyName�?""的记录；
	 *     3.数据库中包含两条相同的记录，返回其中�?�? <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param value 属�?��??.
	 * @return 查询条件.
	 */
	public static Criteria eq(final String propertyName, final Object value) {
		return Criteria.where(propertyName).is(value); 
	}
	
//	/**
//	 * 等于，属性�?�为null或空时参与查�?.. <br>
//	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
//	 * @param propertyName 属�?�名�?.
//	 * @param value 属�?��?�，为null或空也参与查�?.
//	 * @return 查询条件.
//	 */
//	public static Criteria eq2(final String propertyName, final Object value) {
//		if (StringUtil.isNullOrEmpty(value)) {
//			return isEmpty(propertyName);
//		} else {
//    		return Criteria.where(propertyName).is(value); 
//    	}
//	}
	
	/**
	 * 不等于，
	 * 说明�?1.属�?��?�value为null，返回表中的�?条数�?.<br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param value 属�?��??.
	 * @return 查询条件.
	 */
	public static Criteria ne(final String propertyName, final Object value) {
		return Criteria.where(propertyName).ne(value); 
    }
	
//	/**
//	 * 不等于，属�?��?�为null或空时参与查�?.. <br>
//	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
//	 * @param propertyName 属�?�名�?.
//	 * @param value 属�?��?�，为null或空也参与查�?.
//	 * @return 查询条件.
//	 */
//	public static Criteria ne2(final String propertyName, final Object value) {
//		if (value == null) {
//			return isNotNull(propertyName);
//		} else if (StringUtil.isEmptyString(value.toString())) {
//			return isNotEmpty(propertyName);
//		} else {
//			return Criteria.where(propertyName).ne(value); 
//    	}
//    }
	
	/**
	 * like. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param value 属�?��?�，为null或空将不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria like(final String propertyName, final Object value) {
//    	if (!StringUtil.isNullOrEmpty(value)) {
//    		/**
//    		 * 使用正则表达式进行模糊查�?
//    		 * '%value%'
//    		 */
//    		Pattern pattern = Pattern.compile("^.*" + value+ ".*$"); 
//    		return Criteria.where(propertyName).regex(pattern);
//    	} else {
//    		return null;
//    	}
		Pattern pattern = Pattern.compile("^.*" + value+ ".*$"); 
		return Criteria.where(propertyName).regex(pattern);
    }
    
    public static Criteria leftLike(final String propertyName, final Object value)
    {
        Pattern pattern = Pattern.compile("^" + value + ".*$");
        return Criteria.where(propertyName).regex(pattern);
    }
    
    public static Criteria ignoreCase(final String propertyName, final Object value)
    {
        return Criteria.where(propertyName).regex("^" + value + "$", "i");
    }
    
    /**
	 * 大于. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param value 属�?��?�，为null或空将不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria gt(final String propertyName, final Object value) {
//    	if (!StringUtil.isNullOrEmpty(value)) {
//    		return Criteria.where(propertyName).gt(value);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).gt(value);
    }
    
    /**
	 * 小于. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param value 属�?��?�，为null或空将不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria lt(final String propertyName, final Object value) {
//    	if (!StringUtil.isNullOrEmpty(value)) {
//    		return Criteria.where(propertyName).lt(value);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).lt(value);
    }
    
    /**
	 * 小于等于. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param value 属�?��?�，为null或空将不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria le(final String propertyName, final Object value) {
//    	if (!StringUtil.isNullOrEmpty(value)) {
//    		return Criteria.where(propertyName).lte(value);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).lte(value);
    }
    
    /**
	 * 大于等于. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param value 属�?��?�，为null或空将不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria ge(final String propertyName, final Object value) {
//    	if (!StringUtil.isNullOrEmpty(value)) {
//    		return Criteria.where(propertyName).gte(value);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).gte(value);
    }
    
    /**
   	 * 某属性为NULL. <br>
   	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
   	 * @param propertyName 属�?�名�?.
   	 * @return 查询条件.
   	 */
    public static Criteria isNull(final String propertyName) {
    	return Criteria.where(propertyName).is(null);
    }
    
    /**
   	 * 某属性不为NULL. <br>
   	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
   	 * @param propertyName 属�?�名�?.
   	 * @return 查询条件.
   	 */
    public static Criteria isNotNull(final String propertyName) {
    	return Criteria.where(propertyName).ne(null); 
    }
    
    /**
	 * 某属性为�?.. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @return 查询条件.
	 */
    public static Criteria isEmpty(final String propertyName) {
    	return Criteria.where(propertyName).is(""); 
    }
    
    /**
	 * 某属性不为空. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @return 查询条件.
	 */
    public static Criteria isNotEmpty(final String propertyName) {
    	return Criteria.where(propertyName).ne(""); 
    }
        
    /**
	 * between. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param beginValue �?始属性�??.
	 * @param endValue 结束属�?��??.
	 * @return 查询条件.
	 */
    public static Criteria between(final String propertyName, final Object beginValue, final Object endValue) {
    	return Criteria.where(propertyName).gte(beginValue).andOperator(Criteria.where(propertyName).lte(endValue));
    }
    
    /**
	 * in. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param values 属�?��?�连接串，为null或空将不参与查询.
	 * @param regex 属�?��?�连接串的分割字�?.
	 * @return 查询条件.
	 */
    public static Criteria in(final String propertyName, final String values, final String regex) {
//    	if (!StringUtil.isNullOrEmpty(values)) {
//    		return in(propertyName, values.split(regex));
//    	} else {
//    		return null;
//    	}
    	
    	return in(propertyName, values.split(regex));
    }
    
    /**
	 * in. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param values 属�?��?�数组，数组为null或空时不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria in(final String propertyName, final Object[] values) {
    	if (!StringUtil.isNullOrEmpty(values)) {
    		final Collection<Object> idList = new ArrayList<Object>();
    		for (Object id : values) {
    			idList.add(id);
    		}
    		return Criteria.where(propertyName).in(idList);
    	} else {
    		return null;
    	}
    }
    
    /**
	 * in. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param values 属�?��?�列表，集合为null或空时不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria in(final String propertyName, final Collection<?> values) {
//    	if (values != null && values.size() > 0) {
//    		return Criteria.where(propertyName).in(values);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).in(values);
    }
    
	/**
	 * nin. <br>
	 * 
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br>
	 * @param propertyName 属�?�名�?.
	 * @param values 属�?��?�列表，集合为null或空时不参与查询.
	 * @return 查询条件.
	 */
	public static Criteria nin(final String propertyName, final Collection<?> values) {
		if (values != null && values.size() > 0) {
			return Criteria.where(propertyName).nin(values);
		} else {
			return null;
		}
	}

	/**
	 * not. <br>
	 * 
	 * @author qiushaohua 2014-3-4 <br>
	 * @param propertyName 属�?�名�?.
	 * @param criteria 属�?��?�列表，集合为null或空时不参与查询.
	 * @return 查询条件.<br/>
	 *     <pre>
	 *     propertyName: {
	 *         $not: {
	 *             // ...criteria
	 *         }
	 *     }
	 *     </pre>
	 */
//	public static Criteria not(final String propertyName, final Criteria criteria) {
//		if (criteria == null) {
//			return null;
//		}
//		Criteria not = new Criteria("$not").is(criteria.getCriteriaObject());
//		return new Criteria(propertyName).is(not.getCriteriaObject());
//	}
           
    
    /**
	 * and. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param criterions and操作包含的查询条件，Criteria为null的元素不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria and(final Criteria... criterions) {
    	if (criterions == null) {
    		return null;
    	} else {
    		Criteria[] arr = getNotNullCriteria(criterions);
    		if(arr==null)
    			return null;
    		return new Criteria().andOperator(arr);
    	}
    }
    
    /**
     * Description: size
     * $size是匹配数组内的元素数量的，如有一个对象：{a:["foo"]}，他只有�?个元素：
                  下面的语句就可以匹配�?  db.things.find( { a : { $size: 1 } } );
     * Create Date: 2014�?3�?21日上�?11:11:40
     * Author     : User
     * @param propertyName
     * @param value
     * @return
     */
    public static Criteria size(final String propertyName, final int value) {
//    	if (!StringUtil.isNullOrEmpty(value)) {
//    		return Criteria.where(propertyName).size(value);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).size(value);
    }
    /**
     * Description:$exists用来判断�?个元素存�?
     * Create Date: 2014�?3�?26日下�?4:08:38
     * Author     : User
     * @param propertyName
     * @return
     */
    public static Criteria existsTrue(final String propertyName) {
//    	if (!StringUtil.isNullOrEmpty(propertyName)) {
//    		return Criteria.where(propertyName).exists(true);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).exists(true);
    }
    
    /**
     * Description:$exists用来判断�?个元素不存在
     * Create Date: 2014�?3�?26日下�?4:08:38
     * Author     : User
     * @param propertyName
     * @return
     */
    public static Criteria existsFalse(final String propertyName) {
//    	if (!StringUtil.isNullOrEmpty(propertyName)) {
//    		return Criteria.where(propertyName).exists(false);
//    	} else {
//    		return null;
//    	}
    	
    	return Criteria.where(propertyName).exists(false);
    }

    /**
	 * or. <br>
	 * @author chenxiangbai 2014-1-7 上午11:16:26 <br> 
	 * @param criterions or操作包含的查询条件，Criteria为null的元素不参与查询.
	 * @return 查询条件.
	 */
    public static Criteria or(final Criteria... criterions) {
    	if (criterions == null) {
    		return null;
    	} else {
    		Criteria[] arr = getNotNullCriteria(criterions);
    		if(arr==null)
    			return null;
    		return new Criteria().orOperator(arr);
    	}
    }
    
    /**
     * 获取非null的查询条�?.. <br>
     * @author chenxiangbai 2014-1-7 下午3:38:17 <br> 
     * @param criterions 查询条件列表.
     * @return 非null的查询条件列�?.
     */
    private static Criteria[] getNotNullCriteria(final Criteria... criterions) {
    	final List<Criteria> criterionList = new ArrayList<Criteria>();
    	for (Criteria criterion : criterions) {
    		if (criterion != null) {
    			criterionList.add(criterion);
    		}
		}
    	if(criterionList.size()<1){
    		return null;
    	}
    	final Criteria[] queryParamList = new Criteria[criterionList.size()];
    	for (int i = 0; i < criterionList.size(); i++) {
    		queryParamList[i] = criterionList.get(i);
		}
    	
    	return queryParamList;
    }
    
//    /**
//	 * elemMatch. 用于其他接收{@link Criteria} 作为参数的情�?, 例如: <br>
//	 * <pre>
//	 *  QueryParamCreator.not("taskUser",
//	 *      QueryParamCreator.elemMatch(
//	 *          QueryParamCreator.eq("userId", userId)
//	 *      )
//	 *  )
//	 * </pre>
//	 * 
//	 * @author qiushaohua 2014-3-5 <br> 
//	 * @param criteria elemMatch操作包含的查询条件，Criteria为null的元素不参与查询.
//	 * @return 查询条件.<br/>
//	 *     <pre>
//	 *     $elemMatch: {
//	 *         // ...criteria
//	 *     }
//	 *     </pre>
//	 */
//    public static Criteria elemMatch(final Criteria criteria) {
//    	if (criteria == null) {
//    		return null;
//    	}
//    	return Criteria.where("$elemMatch").is(criteria.getCriteriaObject());
//    }

    /**
	 * elemMatch. 例如:<br>
	 * <pre>
	 * QueryParamCreator.elemMatch("taskUser", 
	 *     QueryParamCreator.eq("userId", userId),
	 *     QueryParamCreator.le("userType", 1)
	 * );
	 * </pre>
	 * @author qiushaohua 2014-3-5 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param criterions elemMatch操作包含的查询条件，Criteria为null的元素不参与查询.
	 * @return 查询条件.<br/>
	 *     <pre>
	 *     propertyName: {
	 *         $elemMatch: {
	 *             // ...criteria
	 *         }
	 *     }
	 *     </pre>
	 */
	public static Criteria elemMatch(String propertyName, Criteria... criterions) {
		if (criterions == null || criterions.length == 0) {
    		return null;
    	}
		Criteria[] notNullCriteria = getNotNullCriteria(criterions);
		if (notNullCriteria.length == 0) {
			return null;
		}
		if (notNullCriteria.length == 1) {
			return new Criteria(propertyName).elemMatch(notNullCriteria[0]);
		}
		Criteria and = new Criteria().andOperator(notNullCriteria);
		return new Criteria(propertyName).elemMatch(and);
	}
	
    /**
	 * all. <br>
	 * @author denglingcong 2014-7-3 <br> 
	 * @param propertyName 属�?�名�?.
	 * @param values 属�?��?�列表，要求全部匹配，一般用于子文档/集合属�?�查�?
	 * @return 查询条件.
	 */
    public static Criteria all(final String propertyName, final Collection<?> values) {
    	return Criteria.where(propertyName).all(values);
    }
	
	/**
	 * 创建排序.<br/>
	 * 对于key:<br/>
	 * <ul>
	 * <li>如果是以"-" �?�?, 则是倒序排列</li>
	 * <li>如果不是, 则是正序排列, 注意这里, 不需要带�?"+"</li>
	 * </ul>
	 * 例如:
	 * <pre>
	 * order("endDate", "-createDate")
	 * </pre>
	 * 将按endDate 正序, createDate 倒序排列
	 * @param keys
	 * @return
	 */
	public static List<Order> order(String... keys) {
		List<Order> orders = new ArrayList<Order>();
		if(keys==null || keys.length==0)
			return orders;
		for(String key : keys) {
			Order order = buildOrder(key);
			if (order != null) {
				orders.add(order);
			}
		}
		return orders;
	}

	/**
	 * @param key
	 * @return
	 */
	private static Order buildOrder(final String key) {
		if (key == null) {
			return null;
		}
		if (key.startsWith("-")) {
			String substring = key.substring(1);
			if (substring.equals("")) {
				return null;
			}
			return new Order(Direction.DESC, substring);
		}
		return new Order(Direction.ASC, key);
	}

}
